`timescale 1ns/100ps

`include "sim_glb.sv"

module tc;

localparam          CLK_PRD                 = 5;
localparam          BIT_NUM                 = 15;   // BIT_NUM could not be too big because of Fmax
localparam          CNT_BW                  = $clog2(BIT_NUM+1);
localparam          IDX_BW                  = $clog2(BIT_NUM);
localparam [IDX_BW-1:0] IDX_MAX             = BIT_NUM-1;

reg                                         rst_n;
reg                                         clk;

reg                                         timer_tick;         // cyclic single pulse for overtime checking, interval is longer enough, not used when RLS_OT_CHKEN==1'b0
reg                                         apply_en;           // single pulse
wire                [IDX_BW-1:0]            apply_idx;          // return latency is 1 from apply_en==1'b1
reg                                         rls_en;             // single pulse
reg                 [IDX_BW-1:0]            rls_idx;            // legal rage [0:IDX_MAX], be aligned to rls_en==1'b1
wire                [CNT_BW-1:0]            free_cnt;           // legal range [0:BIT_NUM]
reg                                         cfg_ini_restart;    // single pulse
wire                [5-1:0]                 alm_ilf;            // internal logic fault

initial begin:CRG
    rst_n=1'b0;
    clk=1'b0;
    timer_tick=0;

    fork
        rst_n=#100.5 1'b1;
        forever clk=#CLK_PRD ~clk;
        forever begin
            #100000;
            @(posedge clk);
            timer_tick <=`U_DLY 1'b1;
            @(posedge clk);
            timer_tick <=`U_DLY 1'b0;
        end
    join
end

RGRS_MNG    rgrs;
initial begin:REGRESS
    rgrs = new("tc_fbm_sda", 2);

    rgrs.wait_chks_done(100_000_000);
end

fbm_sda #(
        .BIT_NUM                        (BIT_NUM                        ),	// BIT_NUM could not be too big because of Fmax
        .RLS_OT_CHKEN                   (1'b1                           ) 	// if RLS_OT_CHKEN==1'b1, be sure that any applied IDX must be released during a period of timer_tick
) u_fbm_sda ( 
        .rst_n                          (rst_n                          ),
        .clk                            (clk                            ),

        .timer_tick                     (timer_tick                     ),	// cyclic single pulse for overtime checking, interval is longer enough, not used when RLS_OT_CHKEN

        .apply_en                       (apply_en                       ),	// single pulse
        .apply_idx                      (apply_idx                      ),	// return latency is 1 from apply_en

        .rls_en                         (rls_en                         ),	// single pulse
        .rls_idx                        (rls_idx                        ),	// legal rage [0:IDX_MAX], be aligned to rls_en

        .free_cnt                       (free_cnt                       ),

        .cfg_ini_restart                (cfg_ini_restart                ),	// single pulse
        .alm_ilf                        (alm_ilf                        )	// internal logic fault
);

reg                 [BIT_NUM-1:0]           bitmap;

initial begin:APPLY
    integer             gap;

    apply_en        = 0; 
    rls_en          = 0;
    rls_idx         = 0;
    cfg_ini_restart = 0;

    bitmap = {BIT_NUM{1'b0}};

    @(posedge rst_n);

    #50;
    @(posedge clk);
    cfg_ini_restart <=`U_DLY 1;
    @(posedge clk);
    cfg_ini_restart <=`U_DLY 0;

    repeat(100000) begin
        gap = $urandom_range(0, 10);
        repeat(gap) begin
            @(posedge clk);
        end

        while(free_cnt==0) begin
            @(posedge clk);
        end

        apply_en <=`U_DLY 1'b1;
        @(posedge clk);
        apply_en <=`U_DLY 1'b0;
        @(posedge clk);
        //if (apply_idx!=2)
        bitmap[apply_idx] = 1'b1;
    end
    rgrs.one_chk_done("applying is done.");
end


initial begin:RLS
    integer         gap;
    integer         idx;

    @(posedge rst_n);
    @(posedge clk);

    repeat(100000) begin
        gap = $urandom_range(0, 12);
        idx = $urandom_range(0, IDX_MAX);

        repeat(gap) begin
            @(posedge clk);
        end

        while(bitmap==0) begin
            @(posedge clk);
        end

        while(bitmap[idx]==1'b0) begin
            idx = (idx==IDX_MAX) ? 0 : idx+1;
        end

        rls_en  <=`U_DLY 1'b1;
        rls_idx <=`U_DLY idx;
        @(posedge clk);
        rls_en  <=`U_DLY 1'b0;

        bitmap[idx] = 1'b0;
    end
    rgrs.one_chk_done("releasing is done.");
end

endmodule

